{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "标准库容器默认 **不具备内部并发保护**。一切线程安全保证都基于 C++ 内存模型：只要存在“一个线程写 + 另一个线程读/写”同一对象的情况，就必须采用外部同步手段（锁、原子等）防止数据竞争。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 通用规则（C++11 起统一）\n",
    "\n",
    "| 场景                            | 是否安全               | 说明                                                         |\n",
    "| ------------------------------- | ---------------------- | ------------------------------------------------------------ |\n",
    "| 多线程 **同时只读** 同一个容器  | ✅ 通常安全             | 任意数量线程可调用纯读操作（不修改内部状态），前提是容器在此期间未被其他线程写入。 |\n",
    "| 其中一线程写，其他线程读或写    | ❌ 不安全               | 必须使用 `std::mutex` / `std::shared_mutex` 等同步。         |\n",
    "| 内部 `const` 成员函数           | ⚠️ 不能当做线程安全保证 | `const` 并不意味着无内部修改（例如延迟缓存），仍需防护。     |\n",
    "| 不同容器实例                    | ✅ 安全                 | 每个容器实例独立，互不影响。                                 |\n",
    "| 同一容器的不同元素（指针/引用） | ⚠️ 需谨慎               | 一旦容器结构改变（插入/删除/扩容），可能使其他线程持有的迭代器/引用失效。 |\n",
    "\n",
    "**数据竞争（data race）** 产生即为未定义行为。标准库唯一保证线程安全的场景是：**并发读取（只读）** 与 **不同对象各自访问**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 各类容器的线程安全注意点\n",
    "\n",
    "| 容器类别                             | 读写并发   | 迭代器失效及风险                                           | 特殊说明                                                  |\n",
    "| ------------------------------------ | ---------- | ---------------------------------------------------------- | --------------------------------------------------------- |\n",
    "| `vector`, `string`, `deque`, `array` | 写入需锁   | 插入/删除/扩容会使指针、迭代器、引用失效；读写混用必须同步 | 适合只读共享 + 写操作加锁                                 |\n",
    "| `list`, `forward_list`               | 写入需锁   | 节点删除会使指向该节点的迭代器/引用失效，其他节点仍有效    | 虽为节点容器，但修改依旧需同步                            |\n",
    "| `map`, `set`, `unordered_*`          | 写入需锁   | 插入/删除使指向节点的迭代器失效，读写互斥                  | C++17 `node_handle` 操作同样不具备并发保证                |\n",
    "| `queue`, `stack`, `priority_queue`   | 写入需锁   | 内部封装的是 `deque`/`vector` 等，线程安全性随底层容器     | 常见用法：外层加 `std::mutex` + `std::condition_variable` |\n",
    "| `span`, `string_view`                | 不拥有数据 | 自身仅是“视图”，安全性取决于底层数据是否被并发修改         | 若底层容器被写入，视图读访问也需同步                      |\n",
    "| `pmr` 容器                           | 无特殊保障 | `memory_resource` 大多**非线程安全**，文档会明确说明       | 如 `monotonic_buffer_resource` 明确禁止并发访问           |\n",
    "\n",
    "**总结**：所有标准容器以及与之配套的迭代器、节点句柄等，均需外部同步来保证写操作安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 迭代器与引用的并发问题\n",
    "\n",
    "- 插入/删除/重分配后，其他线程手上的迭代器/指针可能 **悬挂（dangling）**，导致未定义行为。\n",
    "- 将容器元素的地址传给其它线程时，必须确保生命周期与并发写入安全。如果容器会扩容或移动元素，需提前拷贝或加锁保护。\n",
    "- `std::vector<bool>` 等特化容器内部封装压缩位存储，其迭代器是 proxy 对象，多线程访问时仍需同步。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 标准库中少数具备（部分）内部并发保障的构件\n",
    "\n",
    "| 组件                                                 | 线程安全特性                                              | 注意事项                                                     |\n",
    "| ---------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------ |\n",
    "| `std::shared_ptr`                                    | 控制块的引用计数递增/递减是线程安全的                     | 但对同一个 `shared_ptr` 句柄本身的读写需同步；`weak_ptr` 同理 |\n",
    "| `std::atomic<std::shared_ptr>` / `atomic_store` 系列 | 专用原子操作封装                                          | 使用 `<atomic>` 中的重载函数                                 |\n",
    "| `std::locale` global                                 | 标准保证其操作线程安全                                    | 现代实现基本满足                                             |\n",
    "| “初始化一次”机制                                     | 函数内的 **静态局部变量初始化** 在 C++11 起有线程安全保证 | 即常说的 *magic statics*                                     |\n",
    "| `std::call_once` / `std::once_flag`                  | 保证只执行一次                                            | 用于懒加载初始化                                             |\n",
    "| `std::mt19937` 等随机数引擎                          | **非**线程安全                                            | 每个线程独立实例或加锁保护                                   |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 同步工具箱"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 常见示例与推荐实践"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 共享容器读写\n",
    "\n",
    "std::vector<int> data;\n",
    "std::shared_mutex sm;\n",
    "\n",
    "void reader() {\n",
    "    std::shared_lock lock(sm);       // 多读共享\n",
    "    auto sum = std::accumulate(data.begin(), data.end(), 0);\n",
    "    // ...\n",
    "}\n",
    "\n",
    "void writer(int value) {\n",
    "    std::unique_lock lock(sm);       // 写操作独占\n",
    "    data.push_back(value);           // 无数据竞争\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 线程安全队列封装\n",
    "\n",
    "template <class T>\n",
    "class ThreadSafeQueue {\n",
    "public:\n",
    "    void push(T value) {\n",
    "        std::lock_guard lock(m_);\n",
    "        q_.push(std::move(value));\n",
    "        cv_.notify_one();\n",
    "    }\n",
    "\n",
    "    T pop() {\n",
    "        std::unique_lock lock(m_);\n",
    "        cv_.wait(lock, [&]{ return !q_.empty(); });\n",
    "        T value = std::move(q_.front());\n",
    "        q_.pop();\n",
    "        return value;\n",
    "    }\n",
    "\n",
    "private:\n",
    "    std::queue<T> q_;\n",
    "    std::mutex m_;\n",
    "    std::condition_variable cv_;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 原子操作与 `shared_ptr`\n",
    "\n",
    "std::shared_ptr<Node> global_ptr;\n",
    "std::mutex global_mutex;  // 或者使用 std::atomic<std::shared_ptr<Node>>\n",
    "\n",
    "void thread1() {\n",
    "    auto local = std::make_shared<Node>();\n",
    "    std::atomic_store(&global_ptr, local); // 原子存储\n",
    "}\n",
    "\n",
    "void thread2() {\n",
    "    auto local = std::atomic_load(&global_ptr); // 原子读取\n",
    "    if (local) { /* safely use */ }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 容器之外的注意事项\n",
    "\n",
    "- **自定义 allocator**：标准未要求其线程安全；若多个线程共用同一 allocator 实例，应自行加锁。\n",
    "- **`std::pmr::memory_resource`**：大多数资源（如 `monotonic_buffer_resource`）明确声明不支持并发访问。\n",
    "- **`std::regex`**：对象及其内部状态也需外部同步，`regex_constants::match_flag_type` 等操作不可并发混用。\n",
    "- **`std::chrono`** / `std::format` / `std::print`：函数本身是纯函数或局部对象，线程安全取决于使用方式。\n",
    "- **`std::filesystem`**：函数调用通常线程安全，但若多线程同时操作同一文件/路径仍需额外同步。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 学习与实战建议\n",
    "\n",
    "1. **对容器加护栏**：针对每个共享容器建立配套的 `std::mutex` 或 `std::shared_mutex`，在 RAII 锁（`std::lock_guard`/`std::unique_lock`）的帮助下管理生命周期。\n",
    "2. **避免裸迭代器跨线程使用**：传参前先复制需要的数据或加锁保护；迭代器失效极易引起隐晦 bug。\n",
    "3. **封装并发模式**：针对常见模式（生产者-消费者、发布-订阅、读多写少），设计小型线程安全封装，统一使用。\n",
    "4. **利用工具检查**：启用 ThreadSanitizer、Helgrind 等工具帮助捕捉数据竞争。\n",
    "5. **单元测试与压力测试**：对并发容器封装或使用场景多做“高并发”测试，复现潜在竞态。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 结论\n",
    "\n",
    "- 标准容器 + 算法 **本质上是单线程语义**，只提供“线程安全读”的最低保证；任何写操作都需外部同步。\n",
    "- 合理使用 `std::mutex`/`std::shared_mutex`、原子操作及 RAII 封装，可简化并发控制。\n",
    "- 了解迭代器失效规则和内存模型，是避免并发 bug 的关键。\n",
    "- 如果需要高度并发的数据结构，可考虑使用专门的并行库（如 TBB、Folyl、Boost.Lockfree）或自行实现锁分段、无锁结构。\n",
    "\n",
    "把这些规则记在心里，结合实际项目场景逐渐形成习惯，就能在“STL + 多线程”环境下自如驾驭复杂的共享状态。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
